package com.sig.util;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.Days;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 时间处理工具
 *
 * @author sig
 * @since 2019/1/25
 */
public final class TimeUtil {
    /** 当天重置时间戳 */
    private static long dayResetTime;
    /** 明天重置时间戳 */
    private static long tomorrowResetTime;
    /** 昨天重置时间戳 */
    private static long yesterdayResetTime;

    private TimeUtil() {
    }

    /**
     * 重置时间
     */
    public static void resetTime() {
        final Calendar calendar = getZeroCalendar();
        final long tmpResetTime = calendar.getTimeInMillis();
        dayResetTime = tmpResetTime;
        tomorrowResetTime = tmpResetTime + DateUtils.MILLIS_PER_DAY;
        yesterdayResetTime = tmpResetTime - DateUtils.MILLIS_PER_DAY;
    }

    private static Calendar getZeroCalendar() {
        final Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
    }

    /**
     * 获取当天重置时间戳
     *
     * @return
     */
    public static long getCurrentDayResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return dayResetTime;
    }

    /**
     * 获取明天重置时间戳
     *
     * @return
     */
    public static long getTomorrowResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return tomorrowResetTime;
    }

    /**
     * 获取昨天重置时间戳
     *
     * @return
     */
    public static long getYesterdayResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return yesterdayResetTime;
    }

    /**
     * 获取当前时间戳
     *
     * @return
     */
    public static long getCurrentTime() {
        return System.currentTimeMillis();
    }

    /**
     * Timestamp转化为时间戳
     *
     * @param stamp
     * @return
     */
    public static long stamp2Millis(final Timestamp stamp) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(stamp);
        return calendar.getTimeInMillis();
    }

    /**
     * 时间戳转化为Timestamp
     *
     * @param millis
     * @return
     */
    public static Timestamp millis2Stamp(final long millis) {
        return new Timestamp(millis);
    }

    /**
     * 获取当前年份
     *
     * @return
     */
    public static int getCurrentYear() {
        return LocalDate.now().getYear();
    }

    /**
     * 获取当前月份
     *
     * @return
     */
    public static int getCurrentMonth() {
        return LocalDate.now().getMonthValue();
    }

    /**
     * 获取当前星期数
     *
     * @return
     */
    public static int getCurrentWeek() {
        return LocalDate.now().getDayOfWeek().getValue();
    }

    /**
     * 指定格式的日期字符串转化为时间戳
     *
     * @param source
     * @return
     */
    public static long parse(final String source) {
        if (StringUtils.isBlank(source))
            return 0L;
        return parse("y-M-d H:m:s", source);
    }

    /**
     * 日期字符串转化为时间戳
     *
     * @param pattern
     * @param source
     * @return
     */
    public static long parse(final String pattern, final String source) {
        final Calendar calendar = Calendar.getInstance();

        try {
            calendar.setTime(new SimpleDateFormat(pattern).parse(source));
            return calendar.getTimeInMillis();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0L;
    }

    /**
     * 当前时间戳转化为指定格式的日期字符串
     *
     * @return
     */
    public static String format() {
        return format(getCurrentTime());
    }

    /**
     * 时间戳转化为指定格式的日期字符串
     *
     * @param millis
     * @return
     */
    public static String format(final long millis) {
        return format("y-M-d H:m:s", millis);
    }

    /**
     * 时间戳转化为日期字符串
     *
     * @param pattern
     * @param millis
     * @return
     */
    public static String format(final String pattern, final long millis) {
        return new SimpleDateFormat(pattern).format(new Date(millis));
    }

    /**
     * 获取下个整点时间戳
     *
     * @return
     */
    public static long getNextWholeHourTime() {
        final Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, 1);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下个每日重置时间戳
     *
     * @return
     */
    public static long getNextDayResetTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下个星期一重置时间戳
     *
     * @return
     */
    public static long getNextMondayResetTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        if (getCurrentTime() >= calendar.getTimeInMillis())
            calendar.add(Calendar.WEEK_OF_YEAR, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下个每月一号重置时间戳
     *
     * @return
     */
    public static long getNextFirstDayOfMonthResetTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        if (getCurrentTime() >= calendar.getTimeInMillis())
            calendar.add(Calendar.MONTH, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下个周末(星期六或星期日)重置时间戳
     *
     * @return
     */
    public static long getNextWeekendResetTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        if (getCurrentTime() < calendar.getTimeInMillis())
            return calendar.getTimeInMillis();
        final Calendar clone = (Calendar) calendar.clone();
        clone.setFirstDayOfWeek(Calendar.MONDAY);
        clone.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        if (getCurrentTime() >= clone.getTimeInMillis())
            clone.add(Calendar.DAY_OF_WEEK, 6);
        return clone.getTimeInMillis();
    }

    /**
     * 格式化时长
     *
     * @param millis
     * @return
     */
    public static String formatDuring(final long millis) {
        final long days = millis / DateUtils.MILLIS_PER_DAY;
        final long hours = (millis % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR;
        final long minutes = (millis % DateUtils.MILLIS_PER_HOUR) / DateUtils.MILLIS_PER_MINUTE;
        final long seconds = (millis % DateUtils.MILLIS_PER_MINUTE) / DateUtils.MILLIS_PER_SECOND;
        final StringBuilder builder = new StringBuilder(30);
        if (days > 0)
            builder.append(days < 10 ? "0" + days : days).append("天");
        if (hours > 0)
            builder.append(hours < 10 ? "0" + hours : hours).append("时");
        if (minutes > 0)
            builder.append(minutes < 10 ? "0" + minutes : minutes).append("分");
        if (seconds > 0)
            builder.append(seconds < 10 ? "0" + seconds : seconds).append("秒");
        return builder.toString();
    }

    /**
     * 获取间隔天数
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static int daysBetween(final long startTime, final long endTime) {
        return Days.daysBetween(new org.joda.time.LocalDate(startTime), new org.joda.time.LocalDate(endTime)).getDays();
//        final long apartTime = Math.abs(endTime - startTime);
//        int days = (int) (apartTime / DateUtils.MILLIS_PER_DAY);
//        days = days == 0 ? apartTime % DateUtils.MILLIS_PER_DAY > 0 ? 1 : 0 : days;
//        return days;
    }

    /**
     * 当前时间是否周末(星期六或星期日)
     *
     * @return
     */
    public static boolean isWeekend() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        if (getCurrentDayResetTime() == calendar.getTimeInMillis())
            return true;
        final Calendar clone = (Calendar) calendar.clone();
        clone.setFirstDayOfWeek(Calendar.MONDAY);
        clone.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        return getCurrentDayResetTime() == clone.getTimeInMillis();
    }

    /**
     * 获取当前某一时间点的时间戳，如[10,30]即返回当前10:30的时间戳
     *
     * @param times
     * @return
     */
    public static long getTheTime(final List<Integer> times) {
        if (CollectionUtils.isEmpty(times))
            return 0L;
        final Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, times.get(0));
        calendar.set(Calendar.MINUTE, times.get(1));
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前某一时间点的时间戳，如[10,30]即返回当前10:30的时间戳
     *
     * @param hour
     * @param min
     * @return
     */
    public static long getTheTime(final int hour, final int min) {
        final Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, min);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当天零点时间戳
     *
     * @return
     */
    public static long getCurrentDayZeroTime() {
        final Calendar calendar = getZeroCalendar();
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当月第一天零点时间戳
     *
     * @return
     */
    public static long getCurrentFirstDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当月最后一天零点时间戳
     *
     * @return
     */
    public static long getCurrentLastDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下月第一天零点时间戳
     *
     * @return
     */
    public static long getNextFirstDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取下月最后一天零点时间戳
     *
     * @return
     */
    public static long getNextLastDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTimeInMillis();
    }

    /**
     * 获取上月第一天零点时间戳
     *
     * @return
     */
    public static long getPreviousFirstDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取上月最后一天零点时间戳
     *
     * @return
     */
    public static long getPreviousLastDayOfMonthZeroTime() {
        final Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前指定星期数的时间戳
     *
     * @param week 6.星期六
     * @param time 13:00
     * @return
     */
    public static long getWeekTime(final int week, final String time) {
        if (StringUtils.isBlank(time))
            return 0L;
        final String[] times = time.split(":");
        final Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, week + 1);
        calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(times[0]));
        calendar.set(Calendar.MINUTE, Integer.parseInt(times[1]));
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前整分时间戳
     *
     * @return
     */
    public static long getCurrentMinuteTime() {
        final Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前星期指定星期数的零点时间戳
     *
     * @param week 1-7
     * @return
     */
    public static long getCurrentWeekZeroTime(final int week) {
        final Calendar calendar = getZeroCalendar();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, week + 1);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前年份周数
     *
     * @return
     */
    public static int getWeekOfYear() {
        final Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取某个时间戳距离指定天数后的时间戳
     *
     * @param time
     * @param day
     * @return
     */
    public static long getApartDayTime(final long time, final int day) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(time);
        calendar.add(Calendar.DATE, day);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当天累计毫秒数的时间戳
     *
     * @param millis
     * @return
     */
    public static long getCurrentTimeBySeconds(final int millis) {
        Calendar calendar = getZeroCalendar();
        calendar.add(Calendar.MILLISECOND, millis);
        return calendar.getTimeInMillis();
    }
}
